package cn.bellychang.queue.bobo.linkedqueue03addfirstandremovelastwithtail;

import cn.bellychang.iiterface.bobo.Queue;

/**
 * @author: bellychang
 * @date: 2020/2/10
 */
public class LinkedQueue<E> implements Queue<E> {

    private Node dummyHead;

    private Node dummyTail;

    private int size;

    public LinkedQueue() {
        dummyHead = new Node(null, null, null);
        dummyTail = new Node(null, null, null);
        dummyHead.next = dummyTail;
        dummyTail.prev = dummyHead;
        size = 0;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        Node temp = dummyTail.prev;
        while (temp != null && temp.value != null) {
            builder.append(temp.value)
                    .append("->");
            temp = temp.prev;
        }
        String s = builder.length() >= 2 ? builder.toString().substring(0, builder.length() - 2) : builder.toString();
        return "LinkedQueue Head {" + s + "} Tail";
    }

    @Override
    public int getSize() {
        return this.size;
    }

    @Override
    public boolean isEmpty() {
        return this.size == 0;
    }

    @Override
    public void enqueue(E e) {
        addFirst(e);
    }

    @Override
    public E dequeue() {
        return removeLast();
    }

    @Override
    public E getFront() {
        return getLast();
    }

    private void addFirst(E e) {
        Node newNode = new Node(e, null, null);
        newNode.next = dummyHead.next;
        newNode.prev = dummyHead;

        dummyHead.next.prev = newNode;
        dummyHead.next = newNode;
        size++;
    }

    private E removeLast() {
        if (isEmpty()) {
            throw new IllegalArgumentException();
        }
        Node targetNode = dummyTail.prev;
        targetNode.next.prev = targetNode.prev;
        targetNode.prev.next = targetNode.next;
        // set loitering object to gc
        targetNode.prev = null;
        targetNode.next = null;
        size--;
        return targetNode.value;
    }

    private E getLast() {
        if (isEmpty()) {
            throw new IllegalArgumentException();
        }
        return dummyTail.prev.value;
    }


    private class Node {
        private E value;
        private Node prev;
        private Node next;

        public Node(E value, Node prev, Node next) {
            this.value = value;
            this.prev = prev;
            this.next = next;
        }

        @Override
        public String toString() {
            return value.toString();
        }
    }
}
